using System;

namespace msilgc.common
{
    public interface IMethodHandle {
        void Compile();
        void Call(Grain threadDim, Grain blockDim, params object[] args);
        string CompilerMessages { get; set; }
        string GeneratedKernelCode { get; set; }

        bool MeasurePerformance { get; set; }
        double ExecutionTime { get; set; }
    }
    public abstract class BaseMethodHandle : IMethodHandle
    {
        protected BaseMethodHandle() {
            CompilerMessages = string.Empty;
            GeneratedKernelCode = string.Empty;
            ExecutionTime = 0d;
            MeasurePerformance = false;
        }

        public abstract void Compile();

        public void Call(Grain threadDim, Grain blockDim, params object[] args) {
            if (threadDim.X > 512) {
                throw new ArgumentOutOfRangeException("threadDim", "threadDim.X must be <= 512");
            }
            if (threadDim.Y > 512) {
                throw new ArgumentOutOfRangeException("threadDim", "threadDim.Y must be <= 512");
            }
            if (threadDim.Z > 512) {
                throw new ArgumentOutOfRangeException("threadDim", "threadDim.Z must be <= 512");
            }
            Invoke(threadDim, blockDim, args);
        }

        protected abstract void Invoke(Grain threadDim, Grain blockDim, params object[] args);

        public string CompilerMessages { get; set; }
        public string GeneratedKernelCode { get; set; }

        public bool MeasurePerformance { get; set; }
        public double ExecutionTime { get; set; }

        private DateTime _start;
        protected void StartTimer() {
            if(MeasurePerformance) {
                _start = DateTime.Now;
            }
        }
        protected void StopTimer() {
            if(MeasurePerformance) {
                ExecutionTime = (DateTime.Now - _start).TotalSeconds;
            }
        }
    }
}